<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <meta name="description" content="OrgSync">
    <title>注册 - OrgSync</title>
    <link rel="icon" href="/favicon.ico">
    <link rel="apple-touch-icon" href="/logo192.png">
    <link rel="manifest" href="/manifest.json">
    <link rel="stylesheet" href="/libs/bootstrap@5.3.3/css/bootstrap.min.css">
    <link rel="stylesheet" href="/css/verify.css">
    <style>
        html, body {
            height: 100%;
        }

        body {
            background-color: #f5f5f5;
            position: relative;
        }

        .login-box {
            background-color: #ffffff;
            box-shadow: 0px 20px 80px 0px rgba(0, 0, 0, 0.3);
            max-width: 1000px;
            min-width: 320px !important;
            position: absolute;
            top: 38%;
            left: 50%;
            transform: translate(-50%, -38%);
            user-select: none;
        }

        .side-box {
            align-items: flex-start;
            background: linear-gradient(0deg, #041e5e 0%, #00033b 100%);
            display: flex;
            justify-content: flex-start;
            overflow: hidden;
            padding: 0;
            position: relative;
        }

        .side-box::before {
            background: url('/images/login-background.jpg') no-repeat right center;
            background-size: cover;
            display: block;
            content: '';
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }

        .side-box > img,
        .side-box > div {
            position: absolute;
        }

        .side-box > img {
            bottom: 20px;
            left: 16px;
            width: 256px;
        }

        .side-box .logo {
            background-color: #f0f0f0;
            display: flex;
            flex-direction: column;
            justify-content: center;
            top: 24px;
            right: 24px;
            width: 160px;
            height: 50px;
        }

        .side-box .logo img {
            width: 100%;
        }

        .form-sign-up {
            margin: 64px auto 48px;
            max-width: 340px;
            position: relative;
            width: 100%;
        }

        .form-sign-up a {
            text-decoration: none !important;
        }

        .form-sign-up .form-header {
            align-items: flex-end;
            display: flex;
            justify-content: space-between;
        }

        .form-sign-up .form-header h3,
        .form-sign-up .form-header span {
            margin-bottom: 0;
        }

        .form-sign-up .input-box {
            position: relative;
        }

        .form-sign-up .input-box.verification-code {
            display: none;
        }

        .form-sign-up .input-box.verification-code.valid-mobile {
            display: block;
        }

        .form-sign-up .input-box .invalid-tooltip {
            background-color: rgba(255, 255, 255, 0.001);
            cursor: pointer;
            margin: 0;
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            width: 36px;
            z-index: 5;
        }

        .form-sign-up .input-box.verification-code .btn {
            width: 120px !important;
        }

        .form-sign-up .input-box.verification-code .invalid-tooltip {
            right: 120px;
        }

        .agree-input-box.was-validated.invalid {
            background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
            background-position: right calc(.375em + .1875rem) center;
            background-repeat: no-repeat;
            background-size: calc(.75em + .375rem) calc(.75em + .375rem);
            padding-right: calc(1.5em + .75rem);
        }

        .agree-input-box.was-validated.valid {
            background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
            background-position: right calc(.375em + .1875rem) center;
            background-repeat: no-repeat;
            background-size: calc(.75em + .375rem) calc(.75em + .375rem);
            padding-right: calc(1.5em + .75rem);
        }

        .toast-header svg rect {
            fill: #0d6efd;
        }

        .toast-header.success svg rect {
            fill: #198754;
        }

        .toast-header.danger svg rect {
            fill: #dc3545;
        }

        .toast-header.warning svg rect {
            fill: #ffc107;
        }

        @media (max-width: 1199.98px) {
            .login-box {
                box-shadow: none;
            }
        }

        @media (max-width: 767.98px) {
            body {
                background-color: #ffffff;
            }
            .login-box {
                top: 0;
                transform: translate(-50%, 0);
            }
            .side-box {
                height: 85vw;
            }
        }

        @media (max-width: 429.98px) {
            .login-box {
                top: 0;
                left: 0;
                transform: none;
            }
            .side-box {
                display: none;
            }
        }
    </style>
</head>
<body>
    <div class="container login-box">
        <div class="row">
            <div class="col-md-6 ms-md-auto side-box">
                <img src="/images/organization.png" alt="organization">
                <div class="logo">
                    <img src="/images/logo.png" alt="logo">
                </div>
            </div>
            <div class="col-md-6 ms-md-auto">
                <div class="form-sign-up">
                    <form class="needs-validation">
                        <fieldset>
                            <div class="form-header mb-4">
                                <h3>注册</h3>
                                <span class="text-muted">
                                    已有账号？
                                    <a href="/sign_in" class="link-primary">点此登录</a>
                                </span>
                            </div>
                            <input id="token" type="hidden" th:name="${csrfTokenName}" th:value="${csrfTokenValue}">
                            <div class="input-box mb-3">
                                <input type="text" name="username" placeholder="用户名" minlength="2" maxlength="16"
                                       autocomplete="off" class="form-control" oninput="validateInput(this)">
                                <div class="invalid-tooltip"></div>
                            </div>
                            <div class="input-box mb-3">
                                <input type="text" name="mobile" placeholder="手机号码" minlength="11" maxlength="11"
                                       autocomplete="off" class="form-control" oninput="validateInput(this)">
                                <div class="invalid-tooltip"></div>
                            </div>
                            <div class="input-box verification-code mb-3">
                                <div class="input-group">
                                    <input type="text" name="verificationCode" placeholder="验证码" minlength="4" maxlength="4"
                                           autocomplete="off" class="form-control" oninput="validateInput(this)">
                                    <button type="button" class="btn btn-outline-secondary" onclick="sendVerificationCode()">
                                        发送验证码
                                    </button>
                                </div>
                                <div class="invalid-tooltip"></div>
                            </div>
                            <div class="input-box mb-3">
                                <input type="password" name="password" placeholder="密码" minlength="6" maxlength="16"
                                       autocomplete="off" class="form-control" oninput="validateInput(this)">
                                <div class="invalid-tooltip"></div>
                            </div>
                            <div class="input-box agree-input-box">
                                <div class="form-check">
                                    <input id="agree-terms-of-use" type="checkbox" name="agree" value="no"
                                           class="form-check-input" onclick="javascript: return false">
                                    <label for="agree-terms-of-use" class="form-check-label">
                                        我已阅读并同意&nbsp;
                                        <a href="javascript:" onclick="showTermsOfUse(false)">使用条款</a>
                                    </label>
                                </div>
                                <div class="invalid-tooltip"></div>
                            </div>
                            <button type="button" class="btn btn-lg btn-primary w-100 mt-4" onclick="submitForm()">
                                立即注册
                            </button>
                            <p class="text-secondary text-center mt-5 mb-0">© OrgSync 2024</p>
                        </fieldset>
                    </form>
                </div>
            </div>
        </div>
    </div>

    <div id="verify-modal"></div>

    <div id="terms-of-use-modal" class="modal fade">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h4 class="modal-title">网站使用条款</h4>
                </div>
                <div class="modal-body">
                    <p>感谢您访问 OrgSync（以下简称“本网站”）。</p>
                    <p>本网站向特定企业用户开放，提供网易邮件、企业微信、钉钉、飞书等软件间的组织架构及人员信息同步服务。 在使用本网站前，敬请您仔细阅读以下各项使用条款（以下简称“本使用条款”）。您对本网站的使用(包括但不限于对本网站的访问、登录，对本网站内容的浏览和使用)，将被视为您自愿承诺接受本声明的约束。如果您对本使用条款的内容不能接受，您应当立即停止使用本网站并迅速离开。</p>
                    <p><strong>1. 本网站的使用</strong></p>
                    <p>您在注册用户以后，需要填写详细用户信息，然后由管理员进行审核，审核通过以后方可使用本网站进行组织架构与人员信息同步。</p>
                    <p><strong>2. 个人信息的保护</strong></p>
                    <p>我们尊重访问本网站的任何个人的隐私信息。当您访问本网站的时候可能被要求提供您个人的基本资料(如姓名、电子邮件、电话号码、公司、职位等)，您可以自行选择是否提供。对于您提供的个人信息，我们将根据中华人民共和国相关法律进行保密并严格保管，不会将这些信息以任何方式提供或展示给任何第三方。</p>
                    <p><strong>3. 网站的更新与变更</strong></p>
                    <p>我们有权单方面在任何时间，对本网站的内容进行变更或更新，此种变更或更新无需以通知您或任何第三方为前提。您承认并接受上述变更或更新。我们建议您定期访问本网站以尽快获知有关的更新或变更的信息。</p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-danger" onclick="agreeTermsOfUse(false)">拒绝</button>
                    <button type="button" class="btn btn-primary" onclick="agreeTermsOfUse(true)">同意</button>
                </div>
            </div>
        </div>
    </div>

    <div class="toast-container position-fixed bottom-0 end-0 p-3">
        <div id="toast" class="toast">
            <div class="toast-header">
                <svg class="rounded me-2" width="20" height="20" focusable="false" xmlns="http://www.w3.org/2000/svg">
                    <rect width="100%" height="100%"></rect>
                </svg>
                <strong class="me-auto">提示信息</strong>
                <small></small>
                <button type="button" class="btn-close" data-bs-dismiss="toast"></button>
            </div>
            <div class="toast-body"></div>
        </div>
    </div>

    <script src="/libs/bootstrap@5.3.3/js/bootstrap.bundle.min.js"></script>
    <script src="/libs/axios@1.7.2/axios.min.js"></script>
    <script src="/libs/crypto-js@4.0.0/crypto-js.js"></script>
    <script src="/js/verify.js"></script>

    <script>
        var modalVerify = null;
        var modal = null;
        var toast = null;
        var displayNames = {
            username: '用户名',
            mobile: '手机号码',
            verificationCode: '验证码',
            password: '密码',
            agree: '同意'
        };
        var regExps = {
            username: {
                regExp: /^[A-Za-z][A-Za-z\d_-]{0,14}[A-Za-z\d]{1}$/,
                message: '用户名必须由英文字母/数字/下划线（_）/连字符（-）组成，2-16位，且以英文字母开头，不能以下划线或连字符结尾'
            },
            mobile: {
                regExp: /^1[3-9]\d{9}$/,
                message: '请输入正确的11位手机号码'
            },
            verificationCode: {
                regExp: /^\d{4}$/,
                message: '验证码不正确'
            },
            password: {
                regExp: /(?=.*[0-9])(?=.*[a-zA-Z!@_#$%^&*()\-+=,.?]).{6,16}$/,
                message: '密码长度为6-16位，必须包含数字，且必须包含字母或其它字符（!@_#$%^&*()-+=,.?）'
            },
            agree: {
                regExp: /^yes$/,
                message: '请阅读并同意使用条款'
            }
        };
        var tooltipTriggerList = document.querySelectorAll('form .invalid-tooltip');
        var tooltips = {};
        tooltipTriggerList.forEach(function (item) {
            var input = item.parentElement.querySelector('input');
            var tooltip = new bootstrap.Tooltip(item, {
                placement: 'top',
                title: 'tooltip'
            });
            tooltips[input.name] = {
                element: item,
                input: input,
                tooltip: tooltip
            };
            setErrorMessage(input, '');
        });

        function submitForm() {
            var invalidKeys = [];
            for (var key in tooltips) {
                if (!validateInput(tooltips[key].input)) {
                    invalidKeys.push(key);
                }
            }
            if (invalidKeys.length === 1 && invalidKeys[0] === 'agree') {
                showTermsOfUse(true);
            }
            if (invalidKeys.length) {
                return;
            }
            var inputs = document.querySelectorAll('form input');
            var formData = {};
            var tokenInput = null;
            for (var i = 0; i < inputs.length; i++) {
                if (inputs[i].id === 'token') {
                    tokenInput = inputs[i];
                } else {
                    formData[inputs[i].name] = inputs[i].value;
                }
            }
            var headers = {};
            headers[tokenInput.name] = tokenInput.value;
            showFormLoading(true);
            axios.post('/api/user/signUp', formData, {
                headers: headers
            }).then(function (response) {
                showToast('用户注册', '用户注册成功，稍后请登录', 'success');
                var timeoutId = setTimeout(function () {
                    var newUser = {
                        username: formData.username,
                        expiry: new Date().getTime() + 15000
                    };
                    localStorage.setItem('NewUser', JSON.stringify(newUser));
                    clearTimeout(timeoutId);
                    location.href = '/sign_in';
                }, 3000);
            }).catch(function (error) {
                var message = '注册失败';
                var type = 'danger';
                if (error && error.response && error.response.data && error.response.data.message) {
                    message = error.response.data.message;
                    type = 'warning';
                }
                showToast('用户注册', message, type);
                showFormLoading(false);
            });
        }

        function sendVerificationCode() {
            var mobileInput = document.querySelector('input[name="mobile"]');
            if (!validateInput(mobileInput)) {
                mobileInput.focus();
                return;
            }
            showModalVerify();
        }

        function validateInput(input) {
            var displayName = displayNames[input.name];
            getInputBox(input).classList.add('was-validated');
            if (!input.value) {
                setErrorMessage(input, displayName + '为必填项');
                return false;
            }
            if (!regExps[input.name].regExp.test(input.value)) {
                setErrorMessage(input, regExps[input.name].message);
                return false;
            }
            setErrorMessage(input, '');
            if (input.name === 'mobile') {
                document.querySelector('.input-box.verification-code').classList.add('valid-mobile');
            }
            return true;
        }

        function getInputBox(input) {
            var inputBox = input;
            while (true) {
                inputBox = inputBox.parentElement;
                if (inputBox.classList.contains('input-box')) {
                    break;
                }
            }
            return inputBox;
        }

        function setErrorMessage(input, message) {
            var item = tooltips[input.name];
            var inputBox = getInputBox(input);
            input.setCustomValidity(message);
            item.tooltip.setContent({ '.tooltip-inner': message });
            if (message) {
                item.element.style.display = 'block';
            } else {
                item.element.style.display = 'none';
                item.tooltip.hide();
            }
            if (input.name === 'agree') {
                inputBox.classList.remove('invalid');
                inputBox.classList.remove('valid');
                inputBox.classList.add(message ? 'invalid' : 'valid');
            }
        }

        function showFormLoading(loading) {
            document.querySelector('form fieldset').disabled = loading;
            if (loading) {
                document.querySelector('form .form-header .text-muted').classList.add('d-none');
                document.querySelector('form .btn-primary').innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
            } else {
                document.querySelector('form .form-header .text-muted').classList.remove('d-none');
                document.querySelector('form .btn-primary').innerText = '立即注册';
            }
        }

        function showModalVerify() {
            if (!modalVerify) {
                modalVerify = new ModalVerify('#verify-modal', {
                    success: function (data) {
                        var mobile = document.querySelector('input[name="mobile"]').value;
                        var button = document.querySelector('.input-box.verification-code .btn');
                        button.disabled = true;
                        button.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
                        axios.post('/api/sendVerificationCode', {
                            mobile: mobile,
                            usage: 0,
                            captchaVerification: data.captchaVerification
                        }).then(function (response) {
                            button.innerText = '已发送';
                            button.countdown = 61;
                            showToast('发送验证码', '验证码已成功发送', 'success');
                            var intervalId = setInterval(function () {
                                button.countdown = button.countdown - 1;
                                if (button.countdown <= 0) {
                                    clearInterval(intervalId);
                                    button.disabled = false;
                                    button.innerText = '发送验证码';
                                } else {
                                    button.innerText = button.countdown + '秒';
                                }
                            }, 1000);
                        }).catch(function (error) {
                            var message = '验证码发送失败';
                            var type = 'danger';
                            button.disabled = false;
                            button.innerText = '发送验证码';
                            if (error && error.response && error.response.data && error.response.data.message) {
                                message = error.response.data.message;
                                type = error.response.data.code === 500 ? 'danger' : 'warning';
                            }
                            showToast('发送验证码', message, type);
                        });
                    }
                }).init();
            }
            modalVerify.show();
        }

        function agreeTermsOfUse(agree) {
            var input = document.getElementById('agree-terms-of-use');
            input.checked = agree;
            input.value = input.checked ? 'yes' : 'no';
            validateInput(input);
            modal.hide();
            if (document.querySelector('#terms-of-use-modal .modal-footer .btn-primary').innerText === '同意并注册') {
                submitForm();
            }
        }

        function showTermsOfUse(flag) {
            document.querySelector('#terms-of-use-modal .modal-footer .btn-primary').innerText = flag ? '同意并注册' : '同意';
            modal = bootstrap.Modal.getOrCreateInstance('#terms-of-use-modal', { backdrop: 'static', keyboard: false });
            modal.show();
        }

        function showToast(subtitle, message, type) {
            var element = document.getElementById('toast');
            if (!toast) {
                toast = new bootstrap.Toast(element);
            }
            element.querySelector('.toast-header').className = 'toast-header';
            if (type) {
                element.querySelector('.toast-header').classList.add(type);
            }
            element.querySelector('.toast-header small').innerText = subtitle;
            element.querySelector('.toast-body').innerText = message;
            toast.show();
        }
    </script>
</body>
</html>
